import React, {useState, memo} from "react";
import {Card, Button} from 'antd'

// 渲染流程处理
const RenderFlow = {

    Children: () => {
        console.log('子组件重新渲染了')

        const [count, setCount] = useState(0)
        return (
            <div className={'flex-items-center'}>
                <h3>我是子组件,当前count值为:{count};点击后只有子组件重新执行了</h3>
                <Button onClick={() => setCount(count + 1)}>子组件count:+1</Button>
            </div>

        )
    },

    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        return (
            <div>
                <div className={'flex-items-center'}>
                    <h3>我是父组件,当前count值为:{count};点击后父组件和子组件都重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                </div>
                <RenderFlow.Children/>
            </div>
        )
    }
}

const MemoComponents = {

    Children: memo(() => {
        console.log('子组件重新渲染了')
        const [count, setCount] = useState(0)
        return (
            <div className={'flex-items-center'}>
                <h3>我是子组件,当前count值为:{count};点击后只有子组件重新执行了</h3>
                <Button onClick={() => setCount(count + 1)}>子组件count:+1</Button>
            </div>

        )
    }),

    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        return (
            <div>
                <div className={'flex-items-center'}>
                    <h3>我是父组件,当前count值为:{count};点击后只有父组件重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                </div>
                <MemoComponents.Children/>
            </div>
        )
    }
}

const AnewRender = {

    Children: ({count}) => {
        console.log('子组件重新渲染了')

        return (
            <div className={'flex-items-center'}>
                <h3>我是子组件,父组件传入的count值为:{count}</h3>

            </div>

        )
    },

    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        return (
            <div>
                <div className={'flex-items-center'}>
                    <h3>我是父组件,当前count值为:{count};点击后父组件和子组件都重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                </div>
                <AnewRender.Children count={count}/>
            </div>
        )
    }
}

const CacheError = {

    Children: memo(() => {
        console.log('子组件重新渲染了')

        return (
            <div className={'flex-items-center'}>
                <h3>我是子组件</h3>

            </div>

        )
    }),

    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        const arr = [1, 2, 3]
        const fn = () => {
        }
        return (
            <div>
                <div className={'flex-items-center'}>
                    <h3>我是父组件,当前count值为:{count};点击后父组件和子组件都重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                </div>
                {/**
                问题:
                    传入 arr 数据 或者 fn 方法    arr和fn 都是函数局部作用域里 由于组件每次数据更新都会重新渲染数据   所以尽管arr 和fn 未做任何操作  也会引起函数 子组件更新

                 解决办法 :
                 arr 数据使用  useMemo定义
                 fn 操作方法使用 useCallback 定义
                 */}
                <CacheError.Children arr={arr} fn={fn}/>
            </div>
        )
    }
}


export default () => {
    const [count, setCount] = useState(0)
    return (
        <Card hoverable>
            <div style={{display: 'flex', flexDirection: "column", gap: 10}}>
                <h1>React.memo 的使用:</h1>
                <ul>
                    <li>React.memo 可以 <span className={'definition'}>对组件进行缓存</span>,减少不必要的渲染</li>
                    <li>
                        <span className={'definition'}>react的组件渲染规律是:</span> 父组件改变值后 其内部所有子组件
                        都会重新渲染
                        , 子组件改变值 只会重新渲染当前子组件,父组件不会重新渲染 减少性能消耗
                    </li>
                    <li><span className={'definition'}>注:React.memo 与 userMemo 不同</span></li>
                </ul>

                <ul>
                    <h3>重新缓存的情况:</h3>
                    <li>props 属性改变</li>
                    <li>state 组件中的状态改变</li>
                    <li>useContext 值的改变</li>
                </ul>
                <div>
                    <h3> 缓存失败</h3>
                    很多时候，父组件会把<span className={'label-red'}> 数据和操作数据的方法 </span>通过属性传给子组件
                    如果父组件每一次渲染，它的局部数据和方法都重新定义，也就意味着子组件总是接收新的属性值
                    因此，缓存失败，父组件每一次渲染，子组件都会跟着重新渲染（产生无意义的损耗）
                </div>

                <div className={'module'}>
                    <div>加载机制示例:</div>
                    <RenderFlow.Parent/>
                </div>
                <div className={'module'}>
                    <div>使用React.memo缓存子组件:</div>
                    <MemoComponents.Parent/>
                </div>
                <div className={'module'}>
                    <div>使用React.memo缓存子组件 改变 props 重新渲染:</div>
                    <AnewRender.Parent/>
                </div>
                <div className={'module'}>
                    <div>使用React.memo缓存 失败:</div>
                    <CacheError.Parent/>
                </div>
            </div>

        </Card>


    )
}